<template xmlns:v-clipboard="http://www.w3.org/1999/xhtml">
  <div>
    <el-select class="db_select" @change="clearDbSource" v-model="dbType" placeholder="请选择数据库类型">
      <el-option
        v-for="item in options"
        :key="item.label"
        :label="item.label"
        :value="item.value">
      </el-option>
    </el-select>
    <!--脚本上传窗口-->
    <el-dialog title="数据源文件上传" :visible.sync="uploadDialogVisible"
       v-loading="loading"
       element-loading-text="拼命加载中"
       element-loading-spinner="el-icon-loading"
       element-loading-background="rgba(0, 0, 0, 0.8)"
    >
      <el-upload
        class="upload-demo"
        drag
        name="file"
        action="http://127.0.0.1:9001/template/code/upload"
        :headers="headers"
        :on-success="uploadOK"
        :on-error="uploadERR"
        multiple>
        <i class="el-icon-upload"></i>
        <div class="el-upload__text">将文件拖到此处，或<em>点击上传</em></div>
        <div class="el-upload__tip" slot="tip">只能上传.properties文件，且不超过500kb</div>
      </el-upload>
      <div slot="footer" class="dialog-footer">
        <el-button @click="uploadDialogVisible = false">取 消</el-button>
        <el-button type="primary" @click="uploadDialogVisible = false">确 定</el-button>
      </div>
    </el-dialog>

    <span @click="dbSourceClick">
      <el-input class="db_name" @change="getcurConnCount" v-on:change="getcurConnCount" placeholder="添加数据源" v-model="dbName" clearable></el-input>
    </span>

    <el-button class="upload_btn" type="primary" @click="uploadDialogVisible = true">文件上传<i class="el-icon-upload el-icon--right"></i></el-button>
    <el-button class="upload_btn" type="primary" @click="dsFileModuleDownload">模板下载<i class="el-icon-download el-icon--right"></i></el-button>

    <span class="curConnSpan">当前连接数 ：{{count.curConnCount===''? 0 : count.curConnCount}}</span> 
    <!--分割线-->
    <v-divider class="divider"/>
    <!--表单1-->
    <div v-show="dbSourceVisible">
      <el-form ref="form" :model="form" label-width="">
        <el-form-item class="db_item" label="主机IP">
          <el-input class="db_conn" v-model="form.ip" placeholder="请输入IP地址"></el-input>
        </el-form-item>
        <el-form-item class="db_item" label="端口号">
          <el-select class="db_conn" v-model="form.port = dbType === 'Mysql' ? '3306' : '1521'" placeholder="请选择端口号">
            <el-option label="3306" value="3306"></el-option>
            <el-option label="1521" value="1521"></el-option>
          </el-select>
        </el-form-item>
        <el-form-item class="db_item" label="数据库名">
          <el-input class="db_conn" v-model="form.database" placeholder="请输入数据库名"></el-input>
        </el-form-item>
        <el-form-item class="db_item" label="用户名">
          <el-input class="db_conn" v-model="form.username" placeholder="请输入用户名"></el-input>
        </el-form-item>
        <el-form-item class="db_item" label="密码">
          <el-input class="db_conn" v-model="form.password" placeholder="请输入密码" show-password></el-input>
        </el-form-item>
        <el-form-item class="db_item">
          <el-button type="primary" @click="onSubmit">数据库连接测试</el-button>
        </el-form-item>
      </el-form>
    </div>
    <!--表单2-->
    <div class="ruleFormDiv" v-show="ruleFormVisible">
      <el-form :model="ruleForm" :rules="rules" ref="ruleForm" label-width="100px" class="demo-ruleForm">
        <el-form-item class="db2_item" label="数据库表" prop="tableName">
          <el-select v-model="ruleForm.tableName" placeholder="请选择数据表">
            <el-option v-for="(tb,i) in tableNames" :key="i" :label="tb" :value="tb"></el-option>
          </el-select>
        </el-form-item>
        <el-form-item class="db2_item" label="项目名称" prop="proName">
          <el-input v-model="ruleForm.proName" placeholder="项目名称"></el-input>
        </el-form-item>
        <el-form-item class="db2_item" label="包名称" prop="pkgName">
          <el-input v-model="ruleForm.pkgName" placeholder="如：com.itjeffrey"></el-input>
        </el-form-item>
        <el-form-item label="模板类型" prop="modelTypes">
          <el-checkbox-group v-model="ruleForm.modelTypes" @change="handleCheckedModulesChange">
            <el-checkbox v-for="(m, i) in modules" :label="m" :key="i" name="modelTypes"></el-checkbox>
          </el-checkbox-group>
          <el-checkbox :indeterminate="isIndeterminate" v-model="checkAll" @change="handleAllChecked">全选</el-checkbox>
        </el-form-item>
        <el-form-item>
          <el-button type="primary" @click="submitForm('ruleForm')">预览</el-button>
          <el-button type="primary" plain @click="sysGenerate('ruleForm')">系统生成</el-button>
          <el-button type="success" round @click="oneKeyGenerate('ruleForm')">MybatisPlus一键生成</el-button>
          <el-button type="info" plain @click="resetForm('ruleForm')">重置</el-button>
        </el-form-item>
      </el-form>
    </div>

      <!--生成代码详情的对话框-->
      <el-dialog
        title="代码预览"
        :visible.sync="codeDialogVisible" width="60%">
        <div id="codeDialogDiv" style="margin-bottom: 100px;height: 600px;width:100%;">
          <div style="z-index: 5; position: relative; left: 80%; top: 40px;">
<!--            <el-button class="editor-icon-copy"-->
<!--                       v-clipboard:copy="copyMsg"-->
<!--                       v-clipboard:success="copySuccess"-->
<!--                       v-clipboard:error="copyError">复制</el-button>-->
            <el-button class="editor-icon-copy" @click="copyMessage">复制</el-button>
            <el-button class="editor-icon-copy" @click="downLoad">下载</el-button>
          </div>
          <template>
            <el-carousel @change="changeCarousel" :height="codeDialogHeight" :interval="5000" indicator-position="outside">
              <el-carousel-item v-for="(item, i) in codeDatas" :key="i" :label="Object.keys(item)[0]">
                <div :id="'copyId'+i" v-html="Object.values(item)[0]"
                     style="overflow-x: scroll; overflow-y: scroll; width: 100%; height: 100%;"></div>
              </el-carousel-item>
            </el-carousel>
          </template>
          <!--隐藏textarea实现复制-->
          <textarea id="input"></textarea>
          <!--隐藏div-->
<!--          <div class="inputDiv" :id="'inputDiv' + i" v-for="(item, i) in codeDatas" :key="i"-->
<!--               v-html="Object.values(item)[0]"></div>-->
        </div>

        <span slot="footer" class="dialog-footer">
          <el-button @click="codeDialogVisible = false">取 消</el-button>
          <el-button type="primary" @click="codeDialogVisible = false">确定</el-button>
        </span>
      </el-dialog>
    </div>
</template>

<script>
  const moduleOptions = ['bo', 'entity', 'mapper', 'mapper.xml', 'service', 'service.impl', 'controller'];
  export default {
    name: "category",
    props: {
      //设置代码预览弹框的高度
      codeDialogHeight: {
        type: String,
        default: '600px'
      }
    },
    data() {
      return {
        checkAll: false,
        isIndeterminate: true,
        modules: moduleOptions,

        copyMsg: 'This is copy message!',
        isEdit:true,

        // timer: '', //定时器

        //下拉选数据
        options: [{
          value: 'Mysql',
          label: 'Mysql'
        }, {
          value: 'Oracle',
          label: 'Oracle'
        }],
        dbType: 'Mysql', //数据库类型

        dbName: '', //数据库名称

        dbSourceVisible: false,

        loading: true, //数据源文件上传时的加载条

        //脚本上传数据
        uploadDialogVisible: false,

        count: {
          curConnCount: '', //当前连接数
        },

        //表单1数据
        form: {
          dbDriver: '', //数据库驱动
          ip: 'localhost',
          port: '',
          database: '',
          username: '',
          password: ''
        },

        dbSourceClickCount: 0, //添加数据源按钮点击次数

        //表单2数据
        ruleForm: {
          tableName: '',
          proName: '',
          pkgName: '',
          modelTypes: []
        },
        tableNames: [],
        codeDatas: [], //返回的代码数据
        rules: {
          tableName: [
            { required: true, message: '请选择表名', trigger: 'change' }
          ],
          proName: [
            { required: true, message: '请输入项目名', trigger: 'blur' }
            // { min: 3, max: 5, message: '长度在 3 到 5 个字符', trigger: 'blur' }
          ],
          pkgName: [
            { required: true, message: '请输入包名', trigger: 'blur' }
          ],
          modelTypes: [
            { type: 'array', required: true, message: '请至少选择一个模板类型', trigger: 'change'}
          ]
        },

        ruleFormVisible: false,

        codeDialogVisible: false,

        codeViewFlag: true, //代码预览标志，true为首次预览

        entityCode: {
          key: '',
          value: ''
        },
        mapperCode: {
          key: '',
          value: ''
        },
        serviceCode: {
          key: '',
          value: ''
        },
        controllerCode: {
          key: '',
          value: ''
        },
        templateCode: {
          key: '',
          value: ''
        }
      }
    },
    mounted: function(){ //页面一加载完成
      this.getcurConnCount(); //通过后端websocket实时获取连接数
      // this.timer = setInterval(this.getcurConnCount, 60000); //设置1分钟一次的循环定时器获取当前系统连接数
      //websocket获取连接数
      var webSocket;
      var _this = this;
      if(typeof(WebSocket) == "undefined") {
        console.log("您的浏览器不支持WebSocket");
      }
      webSocket = new WebSocket("ws://127.0.0.1:9001/websocket");
      //获取来自服务端的消息
      webSocket.onmessage = function (resp) {
        console.log("来自websocketServer的消息：" + JSON.stringify(resp.data));
        let str = resp.data;
        if(str === undefined){
          return;
        }
        if((typeof str) === 'string' && str !== '连接成功'){
          var s = new String(str).substring(8, 9);
          _this.$set(_this.count, 'curConnCount', s);
        }
      };
      webSocket.onclose = function (e) {
      console.log('websocket 断开: ' + e.code + ' ' + e.reason + ' ' + e.wasClean)
      console.log(e)
  }
    },
    beforeDestroy(){ //页面关闭之前
      // clearInterval(this.timer); //页面关闭之前清除这个定时器
    },
    computed: {
      headers() {
        return {
          // Authentication: "Bearer " + (localStorage.token || "")
          Authentication: this.$store.state.token,
          RefreshToken: this.$store.state.refresh_token
        };
      }
    },
    methods: {
      //js复制文本
      copyMessage(){
        let _this = this;
        let i = 0;
        this.codeDatas.forEach(function (c, k) {
          if(_this.templateCode.key === Object.keys(c)[0]){
            console.log(k, Object.keys(c)[0])
            i = k;
          }
        });
        let text = document.getElementById("copyId" + i).innerText;
        let input = document.getElementById("input");
        input.textContent = text; // 修改文本框的内容
        console.log(text)
        input.select(); // 选中文本
        document.execCommand("copy"); // 执行浏览器复制命令
        console.log("复制成功")
        return i;
      },
      changeCarousel(i1, i2){
        console.log(i1, i2);
        let codeData = this.codeDatas[i1];
        this.templateCode.key = Object.keys(codeData)[0];
        this.templateCode.value = Object.values(codeData)[0];
        this.copyMsg =
          this.templateCode.value.replace(/<br\/>/g, "\\n").replace(/&nbsp;/g, "").replace(/&lt;/g,
            "<").replace(/&gt;/g, ">");
      },
      copySuccess({ value, event }){
        console.log(value);
        this.$message.success("复制成功")
      },
      copyError({ value, event }){
        console.log(value);
        this.$message.error("复制失败")
      },
      handleAllChecked(val){
        this.ruleForm.modelTypes = val ? moduleOptions : [];
        this.isIndeterminate = false;
      },
      handleCheckedModulesChange(value) {
        let checkedCount = value.length;
        this.checkAll = checkedCount === this.modules.length;
        this.isIndeterminate = checkedCount > 0 && checkedCount < this.modules.length;
      },
      dbSourceClick(){
        if(this.dbType === ''){
          this.$message.error("请先选择数据库类型！");
          return false;
        }
        if(this.dbName === ''){
          this.clearDbSource();
          this.clearRuleFormData();
          this.clearViewCodeData();
          this.ruleFormVisible = false;
        }
        this.dbSourceClickCount ++;
        //添加数据源输入框，点击一次显示数据源表单，再点击一次取消显示(奇数显示，偶数不显示)
        this.dbSourceVisible = this.dbSourceClickCount % 2 === 1;

        if(this.dbSourceVisible){
          this.ruleFormVisible = false;
        }
      },

      //获取当前连接数
      getcurConnCount(){
        this.$http.post("/template/code/getcurConnCount", {}).then(resp => {
            if(resp.data.errCode !== 'undefined' && resp.data.errMsg !== 'undefined' && resp.data.errCode===530){
              this.$message.error(resp.data.errMsg);
              return;
            }
            if(resp.data.data !== 'undefined' && resp.data.data >= 0){
              this.count.curConnCount = resp.data.data;
            }
        })
      },

      //一键生成文档
      oneKeyGenerate(formName){
        this.ruleForm.modelTypes = moduleOptions;
        this.$refs[formName].validate((valid) => {
          if(valid){
            this.$http.post("/template/code/oneKeyGenerate", {
                ip: this.form.ip,
                port: this.form.port,
                database: this.form.database,
                dbDriver: this.form.dbDriver,
                username: this.form.username,
                password: this.form.password,
                tableName: this.ruleForm.tableName,
                proName: this.ruleForm.proName,
                pkgName: this.ruleForm.pkgName,
            }).then(resp => {
              if(resp === 'undefined' || resp === null){
                return;
              }
              this.$message.success("一键生成完成！请在当前系统用户目录下查看已生成的" + this.ruleForm.proName + "文件夹.");
            });
          }
        });
      },

      //表单2方法提交
      submitForm(formName) {
        this.$refs[formName].validate((valid) => {
          const entityCode = this.entityCode;
          const mapperCode = this.mapperCode;
          const serviceCode = this.serviceCode;
          const controllerCode = this.controllerCode;
          let params = {};
          if (valid) {
            // const {tableName, proName, ...params} = this.ruleForm;
            params = this.ruleForm;
            params.database = this.dbName;
            if(this.codeViewFlag){ //首次预览需再添加数据源相关参数
              params.dbDriver = this.form.dbDriver;
              params.ip = this.form.ip;
              params.port = this.form.port;
              params.username = this.form.username;
              params.password = this.form.password;
              this.codeViewFlag = false;
            }

            //调后台代码预览接口
            this.$http.post("/template/code/view", params).then(resp => {
              console.log("代码预览响应：" + JSON.stringify(resp));
              if(resp.data.hasOwnProperty("errMsg")){
                this.$message.error(resp.data.errCode + " : " + resp.data.errMsg);
              }
              this.codeDatas = resp.data;
              this.codeDatas.forEach(function (codeData) {
                var key = Object.keys(codeData)[0];
                var value = Object.values(codeData)[0];
                console.log(key);
                console.log(value);
                if(key === 'entity'){
                  entityCode.key = key; //注意：forEach回调函数中this指代Window
                  entityCode.value = value.replace(/[\r\n\r\n]/g, "<br/>");
                }else if(key === 'mapper'){
                  mapperCode.key = key;
                  mapperCode.value = value;
                }else if(key === 'service'){
                  serviceCode.key = key;
                  serviceCode.value = value;
                }else if(key === 'controller'){
                  controllerCode.key = key;
                  controllerCode.value = value;
                }
              });
              this.codeDialogVisible = true;
              //init copyMsg
              this.copyMsg =
                Object.values(this.codeDatas[0])[0].replace(/<br\/>/g, "\\n").replace(/&nbsp;/g, "").replace(/&lt;/g,
                "<").replace(/&gt;/g, ">");
            });
          } else {
            console.log('error submit!!');
            return false;
          }
        });
      },
      //系统生成
      sysGenerate(formName){
        let _this = this;
        this.$refs[formName].validate((valid) => {
          if(valid){
            _this.$http.post("/template/code/view", {
              ip: _this.form.ip,
              port: _this.form.port,
              database: _this.form.database,
              dbDriver: _this.form.dbDriver,
              username: _this.form.username,
              password: _this.form.password,
              tableName: _this.ruleForm.tableName,
              proName: _this.ruleForm.proName,
              pkgName: _this.ruleForm.pkgName,
              modelTypes: _this.ruleForm.modelTypes
            }).then(resp => {
              if(resp.data.hasOwnProperty("errMsg")){
                _this.$message.error(resp.data.errCode + " : " + resp.data.errMsg);
              }
              _this.codeDatas = resp.data;
              //set value for inputDiv
              // for(let (cd, c) in resp.data){
              _this.codeDatas.forEach(function (cd,c) {
                var htmlDivElement = document.createElement('div');
                // htmlDivElement.className = 'inputDiv';
                htmlDivElement.id = 'inputDiv' + c;
                //position: absolute;top: 0;left: 0;opacity: 0;z-index: -20;
                htmlDivElement.style.position = "absolute";
                htmlDivElement.style.top = 0;
                htmlDivElement.style.left = 0;
                htmlDivElement.style.opacity = 0;
                htmlDivElement.style.zIndex = -20;

                htmlDivElement.innerHTML = Object.values(cd)[0];
                var elementById = document.getElementById('codeDialogDiv');
                elementById.appendChild(htmlDivElement);
              });
              // }

              //copy
              let filename = '';
              _this.codeDatas.forEach(function (c, k) {
                let inputDiv = document.getElementById('inputDiv' + k);
                  let text = inputDiv.innerText;
                  console.log(text)
                  let input = document.getElementById("input");
                  input.textContent = text; // 修改文本框的内容
                  input.select(); // 选中文本
                  document.execCommand("copy"); // 执行浏览器复制命令
                  //download
                  let arr = ['entity', 'mapper', 'service', 'controller'];
                  let fn = Object.keys(_this.codeDatas[k])[0];
                  let tb = _this.formatTableName(_this.ruleForm.tableName);
                  if(arr.containsStr(fn)){
                    filename = tb + fn.charAt(0).toUpperCase() + fn.slice(1) + '.java';
                  }else if(fn === 'bo'){
                    filename = tb + 'BO.java';
                  }else if(fn === 'service.impl'){
                    filename = tb + 'ServiceImpl.java';
                  }else if(fn === 'mapper.xml'){
                    filename = tb + 'Mapper.xml';
                  }
                  _this.download(filename, input.textContent);
                  console.log(filename + "文件已生成！");
              });
          });
              // this.$message.success("一键生成完成！请在当前系统用户目录下查看已生成的" + this.ruleForm.proName + "文件夹.");
        }});
      },
      resetForm(formName) {
        this.$refs[formName].resetFields();
      },
      //表单1方法提交
      onSubmit() {
        if(this.dbType === 'Mysql'){
          this.form.dbDriver = 'com.mysql.cj.jdbc.Driver';
        }else if(this.dbType === 'Oracle'){
          this.form.dbDriver = 'com.oracle.jdbc.Driver';
        }
        //调后台数据库测试连接接口
        this.$http.post("/template/code/dbLink", this.form).then(resp => {
          console.log("数据库测试连接响应：" + JSON.stringify(resp));
          if(resp.data.linkResult === "LINK_OK"){
            this.$message.success('连接成功！');
            this.dbSourceVisible = false;
            this.ruleFormVisible = true;
            this.resetForm('ruleForm');
            this.dbName = this.form.database;
            this.tableNames = resp.data.tableNames;
          }else {
            this.$message.error(resp.data.errCode + " : " + resp.data.errMsg);
          }
          // this.clearDbSource();
        });
      },
      //上传成功钩子
      uploadOK(response, file, fileList){
        console.log("文件上传成功的响应：" + JSON.stringify(response));
        if(response.errCode !== 200){
          this.$message.error(response.errCode + " : " + response.errMsg);
          return;
        }
        this.uploadDialogVisible = false;
        this.$message.success(response.errCode + " : " + response.errMsg);
        this.form = response.data;
        this.tableNames = response.data.tableNames;
        this.dbName = this.form.database;
        this.ruleFormVisible = true;
        this.resetForm('ruleForm');
        this.dbSourceVisible = false;
        this.codeDialogVisible = false;
      },
      //上传失败钩子
      uploadERR(err, file, fileList){
        this.$message.error(err);
      },

      //文件模板下载
      dsFileModuleDownload(){
        this.$http({
          method: "get",
          url: "/template/code/dsFileModuleDownload",
          responseType: "blob"
        }).then(resp => {
          let url = window.URL.createObjectURL(new Blob([resp.data])); //创建blob,设置文件类型
          let a = document.createElement('a'); //创建a标签
          a.download = "dsmodule.properties"; //指定文件名
          a.style.display = 'none';
          a.href = url; //创建url
          a.click(); //click事件触发下载
          // URL.revokeObjectURL(a); //释放内存
        });
      },

      download(filename, text) {
        let element = document.createElement('a');
        element.setAttribute('href', 'data:text/plain;charset=utf-8,' + encodeURIComponent(text));
        element.setAttribute('download', filename);

        element.style.display = 'none';
        document.body.appendChild(element);

        element.click();

        document.body.removeChild(element);
      },

      downLoad(){
        let i = this.copyMessage();
        let input = document.getElementById("input");
        let suffix = '';
        let arr = ['bo', 'entity', 'mapper', 'service', 'service.impl', 'controller'];
        let fn = Object.keys(this.codeDatas[i])[0];
        let tb = this.formatTableName(this.ruleForm.tableName);
        suffix = tb + 'Mapper.xml';
        if(arr.containsStr(fn)){
          suffix = tb + fn.charAt(0).toUpperCase() + fn.slice(1) + '.java';
        }
        this.download(suffix, input.textContent);
      },

      //format tableName
      formatTableName(tableName){
        let tn = '';
        tn = tableName;
        if(tn === ''){
          return;
        }
        if(tn.indexOf('_') !== -1){
          let rt = '';
          let ar = tn.split('_');
          ar.forEach(function (a) {
            rt += a.charAt(0).toUpperCase() + a.slice(1);
          });
          return rt;
        }
        return tn.charAt(0).toUpperCase + tn.slice(1);
      },

      //清空数据源
      clearDbSource(){
        this.form.database = '';
        this.form.username = '';
        this.form.password = '';
      },

      //清空表单二数据
      clearRuleFormData(){
        this.ruleForm.tableName = '';
        this.ruleForm.proName = '';
        this.ruleForm.pkgName = '';
        this.ruleForm.modelTypes = [];
      },
      //清空预览代码数据
      clearViewCodeData(){
        this.entityCode.key = '';
        this.entityCode.value = '';
        this.mapperCode.key = '';
        this.mapperCode.value = '';
        this.serviceCode.key = '';
        this.serviceCode.value = '';
        this.controllerCode.key = '';
        this.controllerCode.value = '';
      },
    }
  };

  //数组中是否包含某个字符串
  // 传入字符串 str ，数组 arr
  Array.prototype.containsStr = function (str) {
    let n = this.length;
    while (n--) {
      if (this[n] === str) {
        return true;
      }
    }
    return false;
  }
</script>

<style scoped> /*scoped属性指定下列CSS样式只用于当前组件*/
  .db_select{
    margin-left: 20px;
    margin-bottom: 10px;
  }
  .db_name{
    display: inline-block;
    width: 200px;
  }
  .upload_btn{
    margin-left: 20px;
    margin-bottom: 10px;
  }
  .db_item{
    width: 15%;
    display: inline-block;
    margin-top: 10px;
    margin-left: 20px;
  }
  .db_conn{
    width: 210px;
  }
  .divider{
    margin-top: 10px;
  }
  .ruleFormDiv{
    margin-top: 20px;
  }
  .db2_item{
    display: inline-block;
  }
  /*代码展示样式*/
/*.el-carousel__item div {*/
/*  color: #0f691d;*/
/*  font-size: 18px;*/
/*  opacity: 0.75;*/
/*  line-height: 300px;*/
/*  margin: 0;*/
/*}*/
.el-carousel__item:nth-child(2n) {
  background-color: #d3dce6;
}
.el-carousel__item:nth-child(2n+1) {
  background-color: #d3dce6;
}
/*代码展示样式*/
.curConnSpan{
  display: block;
  text-align: right;
  float: right;
  margin-top: 10px;
  margin-right: 80px;
}
/*使用隐藏textarea来实现复制*/
#input {position: absolute;top: 0;left: 0;opacity: 0;z-index: -10;}
.inputDiv {position: absolute;top: 0;left: 0;opacity: 0;z-index: -20;}
</style>
